from flask import current_app, request
from enums.vis_type_enum import VisTypeEnum
from enums.yes_no_enum import YesNoEnum
from mauth.login_user_holder import LoginUserHolder
from mauth.mtoken import TokenStrategyFactory
from mexception import AssertTool, GlobalErrorEnum
from models.vis_log import VisLog
from services.enums.user_error_enum import UserErrorEnum
from services.vis_log_service import VisLogService
from tools import get_client_ip, md5_encrypt, parse_user_agent
from decorators import Transactional

from models.user import User
from models.user_role import UserRole
from services.rbac_service import RbacService
from datetime import datetime, timedelta


class AuthService:
    """
    权限模块业务处理类
    """

    def __init__(self, db=None):
        if db is not None:
            self.db = db
        else:
            from models import db

            self.db = db

    @Transactional()
    def login(self, form):
        userName = form.userName.data
        password = form.password.data
        # 先根据用户名查
        u = self.db.session.query(User).filter(User.userName == userName).first()
        if u is None:
            # 根据手机号查
            u = self.db.session.query(User).filter(User.mobilePhone == userName).first()
        if u is None:
            # 用户不存在
            VisLogService(model=VisLog).save_vis_log(
                visType=VisTypeEnum.LOGIN,
                account=userName,
                success="N",
                message="登录失败，用户名不存在",
            )
            AssertTool.raise_biz(UserErrorEnum.USER_NOT_EXIST)
        if u.isLocked == YesNoEnum.YES.code:
            VisLogService(model=VisLog).save_vis_log(
                visType=VisTypeEnum.LOGIN,
                account=userName,
                success="N",
                message="登录失败，用户名已被锁定",
            )
            AssertTool.raise_biz(UserErrorEnum.USER_NOT_EXIST)
        salt = u.salt
        dbPassword = u.password
        md5Password = md5_encrypt(password + salt)
        if md5Password != dbPassword:
            VisLogService(model=VisLog).save_vis_log(
                visType=VisTypeEnum.LOGIN,
                account=userName,
                success="N",
                message="登录失败，密码错误",
            )
            AssertTool.raise_biz(UserErrorEnum.USER_NOT_EXIST)
        # token存储
        token_strategy = TokenStrategyFactory.get_instance()
        tokenData = token_strategy.set(self.to_login_user(u))
        res = {"userId": str(u.id), "token": tokenData["token"]}
        VisLogService(model=VisLog).save_vis_log(
            visType=VisTypeEnum.LOGIN, account=userName, success="Y", message="登录成功"
        )
        return res

    @Transactional()
    def logout(self):
        VisLogService(model=VisLog).save_vis_log(
            visType=VisTypeEnum.LOGIN,
            account=LoginUserHolder.get_user_name(),
            success="Y",
            message="登出成功",
        )
        token_strategy = TokenStrategyFactory.get_instance()
        token = request.headers.get(token_strategy.TOKEN_KEY, "")
        token = token.replace("Bearer ", "")
        token_strategy.remove(token)

    def play_user(self, userId):
        """
        模拟用户登录
        """
        user = self.db.session.query(User).filter(User.id == userId).first()
        if user is None:
            AssertTool.raise_biz(GlobalErrorEnum.GL99999999)
        currentUser = LoginUserHolder.get()
        loginUser = self.to_login_user(user)
        if loginUser.get("superAdmin", False) is True and currentUser.get("superAdmin", False) is not True:
            # 非超级管理员不能扮演超级管理员
            AssertTool.raise_biz(GlobalErrorEnum.GL99999999)
        # 追加扮演用户信息
        loginUser["ext"] = {
            "playerToken": currentUser.get("token"),
            "playerUserId": currentUser.get("token"),
            "playUserAccount": currentUser.get("userName"),
            "isPlayer": True,
        }
        loginUser["playerToken"] = currentUser["token"]
        # token存储
        token_strategy = TokenStrategyFactory.get_instance()
        tokenData = token_strategy.set(loginUser)
        res = {"userId": loginUser["userId"], "token": tokenData["token"]}
        return res

    def un_play_user(self):
        """
        取消扮演用户
        """
        currentUser = LoginUserHolder.get()
        userId = currentUser.get("userId")
        token = currentUser.get("playerToken")
        self.logout()
        return {"userId": userId, "token": token}

    def to_login_user(self, u):
        """
        用户信息转成登录用户信息
        """
        userRoleList = self.db.session.query(UserRole).filter(UserRole.userId == u.id)
        roleIds = [ur.roleId for ur in userRoleList]
        rbacService = RbacService()
        perms = ["admin"]
        if u.adminType != 1:
            perms = rbacService.get_perm_in_cache(roleIds, "platform")
        now = datetime.now()
        timeout = current_app.config.get("TOKEN_EXPIRE_TIMEOUT")
        userAgentStr = request.headers.get("User-Agent")
        userAgentDict = parse_user_agent(userAgentStr)
        os = userAgentDict.get("os")
        browser = userAgentDict.get("browser")
        ip = get_client_ip(request)
        loginUser = {
            "id": str(u.id),
            "userId": str(u.id),
            "userName": u.userName,
            "realName": u.realName,
            "perms": perms,
            "superAdmin": u.adminType == 1,
            "roleIds": roleIds,
            "loginTime": now.strftime("%Y-%m-%d %H:%M:%S"),
            "expireTime": (now + timedelta(seconds=timeout)).strftime(
                "%Y-%m-%d %H:%M:%S"
            ),
            "timeout": str(timeout),
            "loginIp": ip,
            "os": os,
            "loginBrowser": browser,
        }
        return loginUser
